package com.ruoyi.common.utils.query;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.annotation.query.*;
import com.ruoyi.common.core.domain.SuperQuery;
import com.ruoyi.common.exception.UtilException;
import javafx.util.Pair;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.List;

/**
 * @description 查询工具类
 * @author chenyun
 * @date 2022/2/12 14:55
 * @version 1.0
 */
public class QueryUtil {

    /**
     * 根据参数对象获取queryWrapper
     * @param superQuery
     * @param page 是否分页
     * @return QueryWrapper
     */
    public static QueryWrapper<T> queryWrapper(SuperQuery<T> superQuery , boolean page) {
        if (superQuery == null) {
            throw new UtilException("入参"+superQuery.getClass()+"不能为空！");
        }
        QueryWrapper<T> queryWrapper = new QueryWrapper();

        for (Field field : superQuery.getClass().getDeclaredFields()) {
            Pair<String, Object> fieldPair = readField(field, superQuery);
            Object fieldValue = fieldPair.getValue();
            if (fieldValue == null || (fieldValue instanceof String && StringUtils.isBlank((String) fieldValue))) {
                continue;
            }
            wrapper(field, fieldPair, queryWrapper);
        }

        String orderBy = StringUtils.isBlank(superQuery.getOrderBy())?superQuery.getDefaultOrderBy() : superQuery.getOrderBy();
        if (StringUtils.isBlank(orderBy) && page) {
            throw new UtilException("分页查询请指定排序");
        }else {
            String[] orderBys = StringUtils.splitPreserveAllTokens(orderBy);
            int length = orderBys.length;
            boolean isAsc = true;
            String column;
            column = orderBys[0];
            if (length >= 2 && StringUtils.equalsIgnoreCase(orderBys[1], "desc")) {
                isAsc = false;
            }
            queryWrapper.orderBy(StringUtils.isNotBlank(column) , isAsc , column);
        }
        return queryWrapper;
    }

    /**
     * 普通查询条件
     * @param superQuery
     * @return
     */
    public static QueryWrapper queryWrapper(SuperQuery superQuery) {
        return queryWrapper(superQuery , false);
    }

    private static Pair<String, Object> readField(Field field, Object obj) {
        String name = field.getName();
        return new Pair<>(name, BeanUtil.getFieldValue(obj, name));
    }

    private static <E> void wrapper(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        if (field.isAnnotationPresent(OR.class)) {
            or(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(EQ.class)) {
            eq(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(Like.class)) {
            like(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(LikeLeft.class)) {
            likeLeft(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(LikeRight.class)) {
            likeRight(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(GE.class)) {
            ge(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(GT.class)) {
            gt(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(LE.class)) {
            le(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(LT.class)) {
            lt(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(IN.class)) {
            in(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(DateTimeRange.class)) {
            dateTimeRange(field, fieldPair, queryWrapper);
        } else if (field.isAnnotationPresent(DateRange.class)) {
            dateRange(field, fieldPair, queryWrapper);
        }

    }

    private static <E> QueryWrapper<E> dateRange(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        DateRange annotation = field.getAnnotation(DateRange.class);
        Object fieldValue = fieldPair.getValue();
        if (fieldValue instanceof List) {
            List<String> dateRange = (List<String>) fieldValue;
            if (CollectionUtils.isNotEmpty(dateRange) && dateRange.size() == 2) {
                String column = getColumn(annotation.value(), fieldPair.getKey());
                LocalDateTime start = DateUtil.parseLocalDateTime(dateRange.get(0));
                LocalDateTime end = DateUtil.parseLocalDateTime(dateRange.get(1));
                if (annotation.startClosed() && annotation.endClosed()) {
                    queryWrapper.between(column, start, end);
                } else {
                    if (annotation.startClosed()) {
                        queryWrapper.ge(column, start);
                    } else {
                        queryWrapper.gt(column, start);
                    }
                    if (annotation.endClosed()) {
                        queryWrapper.le(column, end);
                    } else {
                        queryWrapper.lt(column, end);
                    }
                }
            }
        }
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> dateTimeRange(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        DateTimeRange annotation = field.getAnnotation(DateTimeRange.class);
        Object fieldValue = fieldPair.getValue();
        if (fieldValue instanceof List) {
            List<String> dateRange = (List<String>) fieldValue;
            if (CollectionUtils.isNotEmpty(dateRange) && dateRange.size() == 2) {
                LocalDateTime start = DateUtil.parseLocalDateTime(dateRange.get(0));
                LocalDateTime end = DateUtil.parseLocalDateTime(dateRange.get(1));
                String column = getColumn(annotation.value(), fieldPair.getKey());
                if (annotation.startClosed() && annotation.endClosed()) {
                    queryWrapper.between(column, start, end);
                } else {
                    if (annotation.startClosed()) {
                        queryWrapper.ge(column, start);
                    } else {
                        queryWrapper.gt(column, start);
                    }
                    if (annotation.endClosed()) {
                        queryWrapper.le(column, end);
                    } else {
                        queryWrapper.lt(column, end);
                    }
                }
            }
        }
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> in(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        IN annotation = field.getAnnotation(IN.class);
        Object fieldValue = fieldPair.getValue();
        if (fieldValue instanceof List) {
            List<?> valueList = (List<?>) fieldValue;
            if (CollectionUtils.isNotEmpty(valueList)) {
                queryWrapper.in(getColumn(annotation.value(), fieldPair.getKey()), valueList);
            }
        }
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> lt(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        LT annotation = field.getAnnotation(LT.class);
        queryWrapper.lt(getColumn(annotation.value(), fieldPair.getKey()), fieldPair.getValue());
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> le(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        LE annotation = field.getAnnotation(LE.class);
        queryWrapper.le(getColumn(annotation.value(), fieldPair.getKey()), fieldPair.getValue());
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> gt(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        GT annotation = field.getAnnotation(GT.class);
        queryWrapper.gt(getColumn(annotation.value(), fieldPair.getKey()), fieldPair.getValue());
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> ge(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        GE annotation = field.getAnnotation(GE.class);
        queryWrapper.ge(getColumn(annotation.value(), fieldPair.getKey()), fieldPair.getValue());
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> likeRight(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        LikeRight annotation = field.getAnnotation(LikeRight.class);
        queryWrapper.likeRight(getColumn(annotation.value(), fieldPair.getKey()), fieldPair.getValue());
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> likeLeft(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        LikeLeft annotation = field.getAnnotation(LikeLeft.class);
        queryWrapper.likeLeft(getColumn(annotation.value(), fieldPair.getKey()), fieldPair.getValue());
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> like(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        Like annotation = field.getAnnotation(Like.class);
        queryWrapper.like(getColumn(annotation.value(), fieldPair.getKey()), fieldPair.getValue());
        return queryWrapper;
    }

    private static <E> QueryWrapper<E> eq(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        EQ annotation = field.getAnnotation(EQ.class);
        queryWrapper.eq(getColumn(annotation.value(), fieldPair.getKey()), fieldPair.getValue());
        return queryWrapper;
    }


    private static <E> QueryWrapper<E> or(Field field, Pair<String, Object> fieldPair, QueryWrapper<E> queryWrapper) {
        Object fieldValue = fieldPair.getValue();
        OR annotation = field.getAnnotation(OR.class);
        String[] columns = annotation.value();
        if (field.isAnnotationPresent(EQ.class)) {
            for (int i = 0; i < columns.length; i++) {
                if (i == 0) {
                    queryWrapper.eq(columns[i], fieldValue);
                } else {
                    queryWrapper.or().eq(columns[i], fieldValue);
                }
            }

        } else if (field.isAnnotationPresent(Like.class)) {
            for (int i = 0; i < columns.length; i++) {
                if (i == 0) {
                    queryWrapper.like(columns[i], fieldValue);
                } else {
                    queryWrapper.or().like(columns[i], fieldValue);
                }
            }
        }
        return queryWrapper;
    }

    private static String getColumn(String column, String fieldName) {
        if (StringUtils.isBlank(column)) {
            return com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(fieldName);
        }
        return column;
    }


}
